package com.danco.training.zaneuskaya.domain.service.storage;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.danco.training.zaneuskaya.cswworker.CSVReader;
import com.danco.training.zaneuskaya.cswworker.CSVSaver;
import com.danco.training.zaneuskaya.cswworker.Separator;
import com.danco.training.zaneuskaya.domain.comparator.OrderComparatorByOrderDate;
import com.danco.training.zaneuskaya.domain.comparator.OrderComparatorByPrice;
import com.danco.training.zaneuskaya.domain.comparator.OrderComparatorByState;
import com.danco.training.zaneuskaya.domain.entity.Book;
import com.danco.training.zaneuskaya.domain.entity.Order;
import com.danco.training.zaneuskaya.domain.entity.storage.BookStorage;
import com.danco.training.zaneuskaya.domain.entity.storage.OrderStorage;



public class OrderStorageService implements Serializable{

	
	/**
	 * 
	 */
	private static final long serialVersionUID = -1305548171488123635L;
	private OrderStorage orderStorage ;
	private BookStorage bookStorage ;
	private BookStorageService bookStorageService = BookStorageService.getBookStorageSeviceInstance();
	private static final Logger logger = Logger.getLogger(OrderStorageService.class);
	
	private static OrderStorageService orderStorageServiceInstance;
	
	private OrderComparatorByOrderDate orderComparatorByOrderDate = new OrderComparatorByOrderDate();
	private OrderComparatorByPrice orderComparatorByPrice = new OrderComparatorByPrice();
	private OrderComparatorByState orderComparatorByState = new OrderComparatorByState();
	
	
	
	public OrderStorageService() {
		
		this.orderStorage = OrderStorage.getOrderStorageInstance();
		this.bookStorage = BookStorage.getBookStorageInstance();
	}

	public List<Order> getOrderList(){
		List<Order> res = new ArrayList<Order>();
		res = orderStorage.getOrders();
		logger.trace("Order list");
			return res;
	}
	
	public List<Integer> getOrderListId(){
		List<Integer> res = new ArrayList<Integer>();
		for (Order or :orderStorage.getOrders()) {
			res.add(or.getId())	;			
				}
			
		
		return res;
	
	}
	
	public int generateUnexistedId(){
		int i = 1;
		while(getOrderListId().contains(i)){
			i++;
		}
		return i;
	}
	public List<Order> getExecutedOrders(List<Order> orders){
		List<Order> res = new ArrayList<Order>();
		for (Order order : orders) {
			if (order.isExecuted()) {
					res.add(order);
					
				}
			
		}
		logger.trace("Excecuted orders  are founded");
			return res;
	}
	
	public List<Order> getNotExecutedOrders(List<Order> orders){
		List<Order> res = new ArrayList<Order>();
		for (Order order : orders) {
			if (!order.isExecuted()) {
					res.add(order);
					
				}
			
		}
		logger.trace("Not excecuted orders  are founded");
			return res;
	}
	
	public List<Order> getExecutedOrdersForPeriod(List<Order> orders, Date from, Date to ){
		List<Order> res = new ArrayList<Order>();
		for (Order order : getExecutedOrders(orders)) {
			
				if (order.getOrderDate().after(from)
						&& order.getOrderDate().before(to)) {
					res.add(order);		
				
			}
		}
		logger.trace("Excecuted orders for period are founded");
			return res;
	}

	public List<Order> sortOrdersByOrderDate(List<Order> orders) {
		orders.sort(orderComparatorByOrderDate);
		logger.trace("Orders are sorted by execution date");
		return orders;
	}

	public List<Order> sortOrdersByTotalPrice(List<Order> orders) {
		orders.sort(orderComparatorByPrice);
		logger.trace("Orders are sorted by total price");
		return orders;
	}

	public List<Order> sortOrdersByOrderState(List<Order> orders) {
		orders.sort(orderComparatorByState);
		logger.trace("Orders are sorted by state");
		return orders;

	}

	public List<Order> sortExecutedOrdersByOrderDate(List<Order> orders,
			Date from, Date to) {
		List<Order> res = new ArrayList<Order>();
		res = getExecutedOrdersForPeriod(orders, from, to);
		res.sort(orderComparatorByOrderDate);
		logger.trace("Executed orders are sorted by execution date");
		
		return res;
	}

	public List<Order> sortExecutedOrdersByPrice(List<Order> orders, Date from,
			Date to) {
		List<Order> res = new ArrayList<Order>();
		res = getExecutedOrdersForPeriod(orders, from, to);
		res.sort(orderComparatorByPrice);
		logger.trace("Executed orders are sorted by price");
		return res;
	}
	
	
	
	
	public Order getOrderById( int id){
		for (Order order: orderStorage.getOrders()){
			if ( order.getId()==id){
				logger.trace("Order is founded in Orderstorage by id");
				return order;
			}
			
		}
		logger.info("Order not founded in Orderstorage ");
		return null;
	}

	public boolean addBookToOrder(Order order, Book book) {

		try{
		if (order.getBooks().contains(book)) {
			for (Book b : order.getBooks()) {
				if (b.getId() == book.getId()) {
					b.setQuantity((b.getQuantity()) + 1);
					logger.trace("Instance of the existing book is added in Order");
				}
				
			}
		}
			else{
				book.setQuantity(1);
				order.getBooks().add(book);
				logger.trace("Instance of the new book is added in Order");
			}
		
		order.setTotalPrice(countPrice(order));
		addOrder(order);
		return true;
		}
		catch(Exception e){
			logger.error(e.getMessage(),e);
			return false;
		}
	}

	public boolean removeBookFromOrder(Order order, Book book) {
		try{
		if (order.getBooks().contains(book)){
		if (order.getBooks().remove(book)) {
			order.setTotalPrice(countPrice(order));
			logger.trace("Instance of book is removed from Order");
			
		}
		}
		return true;
		}
		catch (Exception e){
			logger.error(e.getMessage(),e);
		   return false;
		}
		

	}

	

	public double countPrice(Order order) {
		double sum = 0;
		for (Book book : order.getBooks()) {
			sum += book.getPrice()*book.getQuantity();
		}
		return sum;
	}
	
	public Order createOrderCopy(Order order) throws CloneNotSupportedException{
		Order copy;
		
		copy = order.clone();
		copy.setBooks(order.getBooks());
		copy.setExecuted(order.isExecuted());
		copy.setTotalPrice(order.getTotalPrice());
		copy.setOrderDate(order.getOrderDate());
		copy.setId(generateUnexistedId());
		addOrder(copy);
		return copy;
	}

	public boolean addOrder(Order order) {
		
			return orderStorage.getOrders().add(order) ;
			

	}

	public boolean executeOrderById(int id) {

				getOrderById(id).setExecuted(true);
				getOrderById(id).setOrderDate(new Date());

				for (Book b : bookStorage.getBooks()) {
					if (getOrderById(id).getBooks().contains(b)) {
						b.setQuantity(b.getQuantity() - 1);
					}
					else {
						b.setAvailable(false);
					}
				}
				return true;
			
	}

	public boolean rejectOrder(int index) {

		System.out.println("Order is rejected");
		
		return true;
	}

	
	public  void saveOrderListToFile(String file){
		ArrayList<String> res = new ArrayList<String>();
		for (Order b:getOrderList()){
			res.add(entityDetails(b));
		}
		try {
			CSVSaver.saveListToFile(file,res);
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	public ArrayList<Order> readOrders(String file){
		ArrayList<Order> res = new ArrayList<Order>();
		for (int i = 0; i < CSVReader.readList(file).size(); i++) {
			String order[] = CSVReader.readFile(file)[i].split(Separator.SEPARATOR.getS());
			Order or = new Order(Integer.parseInt(order[0]));
			addOrder(or);
			String books[] = order[1].split(Separator.BOOK_SEPARATOR_IN_ORDER.getS());
				for (int j = 0; j < books.length-1; j++){
					addBookToOrder(or, bookStorageService.getBookById(Integer.parseInt(books[j])));
			}
				or.setExecuted(Boolean.parseBoolean(order[2]));
				or.setTotalPrice(Double.parseDouble(order[3]));
			    res.add(or);
		}
		return res;
	}

	public static OrderStorageService getOrderStorageServiceInstance() {
		if(orderStorageServiceInstance == null){
			orderStorageServiceInstance = new OrderStorageService();
		}
		return orderStorageServiceInstance;
	}

	public static String entityDetails(Order t) {
		

		StringBuffer str = new StringBuffer(t.getId() + Separator.SEPARATOR.getS());
		for (Book book : t.getBooks()) {
			str.append(book.getId());
			str.append(Separator.BOOK_SEPARATOR_IN_ORDER.getS());

		}
		str.append(Separator.SEPARATOR.getS());
		str.append(t.isExecuted()+ Separator.SEPARATOR.getS());
		str.append(t.getTotalPrice());
		return str.toString();

	}
	

}
